from operator import truediv
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from array import array
from queue import Queue
from widgetMessage import msgDialog

import usb.util
import sys, threading
import time
from log import logger

# 当libusb报错如下时
# usb.core.USBError: [Errno None] b'libusb0-dll:err [claim_interface] could not claim interface 0, win error: \xb5\xb1\xce\xc4\xbc\xfe\xd2\xd1\xb4\xe6\xd4\xda\xca\xb1\xa3\xac\xce\xde\xb7\xa8\xb4\xb4\xbd\xa8\xb8\xc3\xce\xc4\xbc\xfe\xa1\xa3\r\n'
# 先将\x转换为%, 后缀到www.baidu.com/?wd=后面, 即可转成中文

class UsbPort(QWidget):
    

    def __init__(self, vid, pid):
        super().__init__()

        self.layout = QGridLayout()
        self.dev = None
        self.lineVid = QLineEdit()
        self.linePid = QLineEdit()
        self.lineVid.setText(vid)
        self.linePid.setText(pid)
        self.lineVid.setReadOnly(True)
        self.linePid.setReadOnly(True)
        self.lineVid.setEnabled(False)
        self.linePid.setEnabled(False)

        self.buttonFindUsb = QPushButton("识别USB")
        self.buttonFindUsb.setMinimumHeight(40)

        self.layout.addWidget(QLabel("VID"), 0,0,1,1)
        self.layout.addWidget(QLabel("PID"), 1,0,1,1)
        self.layout.addWidget(self.lineVid, 0,1,1,2)
        self.layout.addWidget(self.linePid, 1,1,1,2)
        self.layout.addWidget(self.buttonFindUsb, 2,0,1,3)

        self.buttonFindUsb.clicked.connect(self.findUsb)
        self.setLayout(self.layout)
    
    def vid(self):
        return int(self.lineVid.text(), 16)

    def pid(self):
        return int(self.linePid.text(), 16)

    def find(self):
        if self.dev is None:
            self.dev = usb.core.find(idVendor=self.vid(), idProduct=self.pid())
            if self.dev is not None:
                self.dev.set_configuration()        # 必须要加这一句, 否则报invalid configuration 0 错误
        return self.dev
    def release(self):
        self.dev = None

    def findUsb(self):
        if self.find() is not None:
            msgDialog("提示", "成功找到usb")
        else:
            msgDialog("错误", "未找到usb")

    def device(self):
        return self.dev
        


class UsbRead(threading.Thread):

    def __init__(self, usb:UsbPort, ep, usbQueue: Queue=None ):
        super(self.__class__, self).__init__()
        self.usb = usb
        self.usbQueue = usbQueue
        self.ep = ep
        self.hasGotExitSignal = False
        self.totalSize = 0
        self.fileName = 0
        self.daemon = True

    def setQueue(self, queue: Queue):
        self.usbQueue = queue

    def fileSize(self):
        if self.totalSize > (1024 * 1024):
            return "%.2fMB" % (self.totalSize / (1024 * 1024))
        else:
            return "%.2fKB" % (self.totalSize / (1024))

    def read(self, ep):
        try:
            recv = self.usb.device().read(0x80 + ep, 80960, 1000)
            # logger.info(type(recv))
            # logger.info(recv)
            return recv
        except usb.core.USBError as e:
            errorInfo = e.strerror.decode("gbk")
            if 'timeout' in errorInfo:
                return array('B', [])
            else:
                logger.info(errorInfo)
                self.usb.release()
                return None

    def exit(self):
        self.hasGotExitSignal = True

    def run(self):
        logger.info("[info] USB read thread start, ep=%d" % self.ep)
        
        # 日志文件名为 date-epn.log
        self.fileName = time.strftime("./log/" + "%m-%d-%H-%M", time.localtime()) + "-ep" + str(self.ep) + ".log"
        
        with open(self.fileName, "wb") as f:
            logger.info("[info] open file %s successfully" % self.fileName)
            while True:
                # 获取退出信号
                if self.hasGotExitSignal is True:
                    break

                # 正常读取
                result = self.read(self.ep)
                if result is None:
                    break
                elif len(result) == 0:
                    continue
                else:
                    # 有队列的情况下发送到中间屏幕上
                    if self.usbQueue is not None:
                        a = array("B", result).tostring()
                        self.usbQueue.put(a.decode("utf8"))

                    self.totalSize += len(result)
                    logger.info("get data from ep%d, count=%d logSize=%s" % (self.ep, len(result), self.fileSize()))
                    f.write(result)
            

        logger.info("[info] USB read thread exit, ep=%d" % self.ep)



# test
if __name__ == '__main__':

    app = QApplication(sys.argv)
    win = UsbPort()
    win.show()
    sys.exit(app.exec_())

    # set the active configuration. With no arguments, the first
    # configuration will be the active one

    # logger.info(dev.write(0x01, "hello my frienthello my frienthello my frienthello my frienthello my frienthello my frienthello my frienthello my frient"))
    # while True:
    #     try:
    #         recv = dev.read(0x83, 1024, -1)
    #     except:
    #         break
            
    #     a = array("B", recv).tostring()
    #     logger.info(a.decode("utf8"))

    # # get an endpoint instance
    # cfg = dev.get_active_configuration()
    # intf = cfg[(0,0)]
    # logger.info(dir(cfg))

    # ep = usb.util.find_descriptor(
    #     intf,
    #     # match the first OUT endpoint
    #     custom_match = \
    #     lambda e: \
    #         e.bEndpointAddress == 0x83)

    # assert ep is not None
    # logger.info(ep.bEndpointAddress)
    # # write the data
    # logger.info(ep.read(10, timeout=-1).__len__())